package com.qcby.llmtchstd.controller;

import com.google.gson.Gson;
import com.qcby.llmtchstd.common.ResponseResult;
import com.qcby.llmtchstd.entity.*;
import com.qcby.llmtchstd.service.ErrorNoteService;
import com.qcby.llmtchstd.service.StudentExamService;
import com.qcby.llmtchstd.utils.LLMClient;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping(value = "/studentexam")
public class StudentExamController {
    @Autowired
    private StudentExamService studentExamService;

    @Autowired
    private ErrorNoteService errorNoteService;
    // 用于解析JSON响应的ObjectMapper
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @GetMapping("/select")
    public ResponseResult<List<Exam>> selectAll() {
        List<Exam> list = studentExamService.selectAll();
        if (list != null && !list.isEmpty()) {
            return ResponseResult.success("查询成功", list);
        } else {
            return ResponseResult.fail("4003", "查询失败，无数据或查询异常");
        }
    }
    @GetMapping("/selectStudent")
    public ResponseResult<List<Exam>> selectStudent(HttpSession session) {
        User loginUser = (User) session.getAttribute("loginUser");
        int id = loginUser.getId();
        String name = loginUser.getName();
        System.out.println("id-------------"+id);
        List<Exam> list = studentExamService.selectStudent(id);
        for(int i = 0; i<list.size(); i++){
            list.get(i).setCreatorName(name);
        }
        System.out.println(list);
        if (list != null && !list.isEmpty()) {
            return ResponseResult.success("查询成功", list);
        } else {
            return ResponseResult.fail("4003", "查询失败，无数据或查询异常");
        }
    }
    @GetMapping("/selectone")
    public ResponseResult<Exam> selectOne(int id) {  // 修正方法名拼写错误 selecOne -> selectOne
        Exam exam = studentExamService.selectOne(id);

        if (exam != null) {
            return ResponseResult.success("查询成功", exam);
        } else {
            return ResponseResult.fail("4003", "查询失败，无数据或查询异常");
        }
    }
    // 将 @RequestBody 改为直接接收参数或使用 @RequestParam
    @GetMapping("/ifnot")
    public ResponseResult<IfNotExam> ifNot(@RequestParam("examId") int examId, HttpSession httpSession) {  // 从session获取学生ID
        User loginUser = (User) httpSession.getAttribute("loginUser");
        System.out.println("-----------------------"+examId+"---------"+loginUser.getId());
        IfNotExam ans = studentExamService.ifNot(examId, loginUser.getId());
        if (ans != null) {
            return ResponseResult.success("参加过考试", ans);
        } else {
            return ResponseResult.success("未参加考试", null);        }
    }
    @PostMapping("/insertone")
    public ResponseResult<Integer> insertOne(@RequestBody IfNotExam ifNotExam,HttpSession httpSession) {  // 修正方法名拼写错误 selecOne -> selectOne
        User loginUser = (User) httpSession.getAttribute("loginUser");
        Integer ans = studentExamService.insertOne(ifNotExam.getExamId(),loginUser.getId());
        if (ans != null) {
            return ResponseResult.success("查询成功", ans);
        } else {
            return ResponseResult.fail("4003", "查询失败，无数据或查询异常");
        }
    }
    @PostMapping("/save")
    public ResponseResult<Map<String, Object>> save(@RequestBody ExamAnswer examAnswer, HttpSession httpSession) {
        // 获取当前登录用户信息
        User loginUser = (User) httpSession.getAttribute("loginUser");
        if (loginUser == null) {
            return ResponseResult.fail("401", "用户未登录");
        }

        try {
            String answer = examAnswer.getAnswer();
            int examId = examAnswer.getExamId();

            // 获取考试题目信息
            Exam exam = studentExamService.selectOne(examId);
            if (exam == null) {
                return ResponseResult.fail("4004", "未找到对应考试");
            }

            // 构建发给LLM的消息：题目+学生答案
            String userMessage = "考试题目: " + exam + "\n我的答案: " + answer;

            String formatInstruction = "【格式红线：绝对优先，违反即无效】\n" +
                    "1. 输出必须是**纯JSON字符串**，仅包含标准JSON字符（{}[]\"':,.-_@#$%^&*()），从第一个`{`开始，到最后一个`}`结束。\n" +
                    "2. 严禁出现：反引号```（包括```json标记）、文字说明、注释、空行、非JSON字符（如`、~、!），任何多余内容直接导致结果无效。\n" +
                    "\n" +
                    "【核心强制规则：未作答题目必须全量纳入错题（无任何例外）】\n" +
                    "- 未作答判定范围（覆盖所有题型，只要符合以下任一情况，**必须**计入错题并得0分）：\n" +
                    "  ① 作答内容为空白（包括空字符串、仅空格/换行）；\n" +
                    "  ② 作答内容为无意义文字（如“无”“略”“不知道”“不清楚”“未答”）；\n" +
                    "  ③ 作答内容与题目无关（如答非所问、乱码、随机字符、重复题干）；\n" +
                    "  ④ 选择题未选择任何选项（如空选项、“无”）；\n" +
                    "  ⑤ 填空题仅填写标点/符号（无实际内容）；\n" +
                    "  ⑥ 简答题/计算题仅写“不会”“没学过”等无效表述。\n" +
                    "- 检查要求：逐题核对作答内容，**必须100%覆盖所有未作答题目**，漏判一题即视为整体结果无效。\n" +
                    "\n" +
                    "【评分依据与范围】\n" +
                    "- 基于提供的「考试题目」（含ID、题型、分值、题干、选项、标准答案）和「作答内容」（对应ID的具体作答）评分。\n" +
                    "- 唯一标准：作答与标准答案的匹配度，与表述流畅度、篇幅无关。\n" +
                    "\n" +
                    "【其他评分规则（无例外）】\n" +
                    "1. 分数限制：每题得分∈[0, 该题分值]（整数），总分=各题得分总和（精确无误差）。\n" +
                    "\n" +
                    "【分题型细则（逐字对照）】\n" +
                    "- 选择题/判断题：选项完全一致（含大小写）得满分，否则0分。\n" +
                    "- 填空题：\n" +
                    "  - 完全匹配（含文字、符号、标点、大小写）得满分；\n" +
                    "  - 核心信息正确但有非关键错误（如漏“的”），按正确比例给分（四舍五入）；\n" +
                    "  - 核心错误则0分。\n" +
                    "- 简答题/论述题：\n" +
                    "  - 按覆盖「标准答案核心得分点」的比例给分（权重均等，四舍五入）；\n" +
                    "  - 未覆盖任何核心点或完全相悖则0分。\n" +
                    "- 计算题：\n" +
                    "  - 步骤完整正确且结果一致得满分；\n" +
                    "  - 步骤正确但结果错，按关键步骤完成比例给分；\n" +
                    "  - 步骤错、无步骤仅结果对、结果错且步骤不完整均0分。\n" +
                    "\n" +
                    "【JSON结构（字段严格匹配，不得增删）】\n" +
                    "{\n" +
                    "  \"score\": 总分（整数）,\n" +
                    "  \"mistakes\": [\n" +
                    "    {\n" +
                    "      \"questionId\": 错题ID（与原题完全一致）,\n" +
                    "      \"questionType\": 题型（如“选择题”，不得自定义）,\n" +
                    "      \"questionContent\": 仅题干（无选项）,\n" +
                    "      \"options\": 客观题完整选项（如“A.xxx；B.xxx”，主观题留空）,\n" +
                    "      \"yourAnswer\": 作答原样（含错误/空白/无效内容）,\n" +
                    "      \"correctAnswer\": 原题标准答案,\n" +
                    "      \"reason\": 错误原因（未作答必须写明：“未填写有效内容，未掌握该题涉及的[具体知识点，如‘三角函数定义’]”；其他错误按之前示例）,\n" +
                    "      \"yourScore\": 0（未作答固定得0分）\n" +
                    "    },\n" +
                    "    // 其他错题...\n" +
                    "  ]\n" +
                    "}\n" +
                    "- 全对时，\"mistakes\"必为[]（空数组）；若有未作答题目，\"mistakes\"中必须包含所有未作答题目条目。\n" +
                    "\n" +
                    "【最终校验清单（必须全部通过）】\n" +
                    "1. 未作答题目100%纳入错题列表，无遗漏；\n" +
                    "2. 每题得分在[0, 分值]区间；\n" +
                    "3. 总分=各题得分之和（无计算误差）；\n" +
                    "4. 客观题\"options\"与原题完全一致；\n" +
                    "5. \"questionContent\"仅含题干；\n" +
                    "6. 错误原因包含具体差异和关联知识点（未作答必须关联具体知识点）；\n" +
                    "7. JSON格式合法（无语法错误，字段类型正确）。";

            String llmResponse = LLMClient.getLLMResponse2(userMessage, formatInstruction);

            // 解析LLM返回的JSON响应
            JsonNode aiReply = parseLLMResponse(llmResponse);
            if (aiReply == null) {
                return ResponseResult.fail("5001", "解析AI评分结果失败");
            }

            // 提取分数（可以根据需要保存到数据库）
            int score = aiReply.has("score") ? aiReply.get("score").asInt() : 0;
            JsonNode jsonNode = aiReply.get("mistakes");
//            System.out.println(jsonNode);
            List<String> mistakesList = new ArrayList<>();
            for(JsonNode node : jsonNode){
//                System.out.println(node);

                Gson gson = new Gson();
                ErrorNote errorNote = gson.fromJson(node.toString(), ErrorNote.class);
//                System.out.println(loginUser.getId());
                errorNote.setStudentId(loginUser.getId());
                errorNote.setExamId(examId);
//                System.out.println(node);
                System.out.println(errorNote);
                errorNoteService.addError(errorNote);
            }
            // 保存考试结果（包含学生ID、考试ID、答案和分数）
            Integer result = studentExamService.save(
                    answer,
                    examId,
                    loginUser.getId(),  // 使用登录用户的ID
                    score               // 传入AI评分
            );
            if (result != null && result > 0) {
                Map<String, Object> data = new HashMap<>();
                data.put("score", score); // 放入成绩
                data.put("result", result); // 保留原有保存结果（可选）
                return ResponseResult.success("保存成功", data);
            } else {
                return ResponseResult.fail("4003", "保存失败");
            }

        } catch (IOException e) {
            e.printStackTrace();
            return ResponseResult.fail("5000", "调用AI评分服务失败: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.fail("500", "服务器处理异常");
        }
    }

    /**
     * 解析LLM返回的JSON响应
     */
    private JsonNode parseLLMResponse(String llmResponse) {
        try {
            // 解析原始JSON响应
            JsonNode rootNode = objectMapper.readTree(llmResponse);

            // 根据Deepseek API的响应结构，提取choices中的content
            if (rootNode.has("choices") && rootNode.get("choices").isArray() &&
                    rootNode.get("choices").size() > 0) {

                JsonNode contentNode = rootNode.get("choices").get(0).get("message").get("content");
                // 解析AI返回的内容（因为AI返回的是JSON格式的字符串）
                return objectMapper.readTree(contentNode.asText());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
